home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Space & Astronomy
/
Space and Astronomy (October 1993).iso
/
mac
/
VIEWERS
/
X11
/
XLOADIMG.TAR
/
send.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-20
|
17KB
|
629 lines
/* send.c:
*
* send an Image to an X pixmap
*
* jim frost 10.02.89
*
* Copyright 1989, 1990, 1991 Jim Frost.
* See included file "copyright.h" for complete copyright information.
*/
#include "copyright.h"
#include "xloadimage.h"
static int GotError;
static int pixmapErrorTrap(disp, pErrorEvent)
Display *disp;
XErrorEvent * pErrorEvent;
{
#define MAXERRORLEN 100
char buf[MAXERRORLEN+1];
GotError = 1;
XGetErrorText(disp, pErrorEvent->error_code, buf, MAXERRORLEN);
printf("serial #%d (request code %d) Got Error %s\n",
pErrorEvent->serial,
pErrorEvent->request_code,
buf);
return(0);
}
Pixmap ximageToPixmap(disp, parent, ximageinfo)
Display *disp;
Window parent;
XImageInfo *ximageinfo;
{
int (*old_handler)();
Pixmap pixmap;
GotError = 0;
old_handler = XSetErrorHandler(pixmapErrorTrap);
XSync(disp, False);
pixmap= XCreatePixmap(disp, parent,
ximageinfo->ximage->width, ximageinfo->ximage->height,
ximageinfo->depth);
(void)XSetErrorHandler(old_handler);
if (GotError)
return(None);
ximageinfo->drawable= pixmap;
sendXImage(ximageinfo, 0, 0, 0, 0,
ximageinfo->ximage->width, ximageinfo->ximage->height);
return(pixmap);
}
/* find the best pixmap depth supported by the server for a particular
* visual and return that depth.
*
* this is complicated by R3's lack of XListPixmapFormats so we fake it
* by looking at the structure ourselves.
*/
static unsigned int bitsPerPixelAtDepth(disp, scrn, depth)
Display *disp;
int scrn;
unsigned int depth;
{
#if 1 /* the way things are */
unsigned int a;
for (a= 0; a < disp->nformats; a++)
if (disp->pixmap_format[a].depth == depth)
return(disp->pixmap_format[a].bits_per_pixel);
#else /* the way things should be */
XPixmapFormatValues *xf;
unsigned int nxf, a;
xf = XListPixmapFormats(disp, &nxf);
for (a = 0; a < nxf; a++)
if (xf[a].depth == closest_depth)
return(disp->pixmap_format[a].bits_per_pixel);
#endif
/* this should never happen; if it does, we're in trouble
*/
fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
exit(1);
}
XImageInfo *imageToXImage(disp, scrn, visual, ddepth, image, private_cmap, fit,
verbose)
Display *disp;
int scrn;
Visual *visual; /* visual to use */
unsigned int ddepth; /* depth of the visual to use */
Image *image;
unsigned int private_cmap;
unsigned int fit;
unsigned int verbose;
{ Pixel *index, *redvalue, *greenvalue, *bluevalue;
unsigned int a, b, newmap, x, y, linelen, dpixlen, dbits;
XColor xcolor;
XGCValues gcv;
XImageInfo *ximageinfo;
Image *orig_image;
goodImage(image, "imageToXimage");
xcolor.flags= DoRed | DoGreen | DoBlue;
index= redvalue= greenvalue= bluevalue= NULL;
orig_image= image;
ximageinfo= (XImageInfo *)lmalloc(sizeof(XImageInfo));
ximageinfo->disp= disp;
ximageinfo->scrn= scrn;
ximageinfo->depth= 0;
ximageinfo->drawable= None;
ximageinfo->foreground= ximageinfo->background= 0;
ximageinfo->gc= NULL;
ximageinfo->ximage= NULL;
/* process image based on type of visual we're sending to
*/
switch (image->type) {
case ITRUE:
switch (visual->class) {
case TrueColor:
case DirectColor:
/* goody goody */
break;
default:
if (visual->bits_per_rgb > 1)
image= reduce(image, depthToColors(visual->bits_per_rgb), verbose);
else
image= dither(image, verbose);
}
break;
case IRGB:
switch(visual->class) {
case TrueColor:
case DirectColor:
/* no problem, we handle this just fine */
break;
default:
if (visual->bits_per_rgb < 2)
image= dither(image, verbose);
break;
}
case IBITMAP:
/* no processing ever needs to be done for bitmaps */
break;
}
/* do color allocation
*/
switch (visual->class) {
case TrueColor:
case DirectColor:
{ Pixel pixval;
unsigned int redcolors, greencolors, bluecolors;
unsigned int redstep, greenstep, bluestep;
unsigned int redbottom, greenbottom, bluebottom;
unsigned int redtop, greentop, bluetop;
redvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
greenvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
bluevalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
if (visual == DefaultVisual(disp, scrn))
ximageinfo->cmap= DefaultColormap(disp, scrn);
else
ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
visual, AllocNone);
retry_direct: /* tag we hit if a DirectColor allocation fails on
* default colormap */
/* calculate number of distinct colors in each band
*/
redcolors= greencolors= bluecolors= 1;
for (pixval= 1; pixval; pixval <<= 1) {
if (pixval & visual->red_mask)
redcolors <<= 1;
if (pixval & visual->green_mask)
greencolors <<= 1;
if (pixval & visual->blue_mask)
bluecolors <<= 1;
}
/* sanity check
*/
if ((redcolors > visual->map_entries) ||
(greencolors > visual->map_entries) ||
(bluecolors > visual->map_entries)) {
fprintf(stderr, "\
Warning: inconsistency in color information (this may be ugly)\n");
}
redstep= 256 / redcolors;
greenstep= 256 / greencolors;
bluestep= 256 / bluecolors;
redbottom= greenbottom= bluebottom= 0;
for (a= 0; a < visual->map_entries; a++) {
if (redbottom < 256)
redtop= redbottom + redstep;
if (greenbottom < 256)
greentop= greenbottom + greenstep;
if (bluebottom < 256)
bluetop= bluebottom + bluestep;
xcolor.red= (redtop - 1) << 8;
xcolor.green= (greentop - 1) << 8;
xcolor.blue= (bluetop - 1) << 8;
if (! XAllocColor(disp, ximageinfo->cmap, &xcolor)) {
/* if an allocation fails for a DirectColor default visual then
* we should create a private colormap and try again.
*/
if ((visual->class == DirectColor) &&
(visual == DefaultVisual(disp, scrn))) {
ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
visual, AllocNone);
goto retry_direct;
}
/* something completely unexpected happened
*/
fprintf(stderr, "\
imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
return(NULL);
}
/* fill in pixel values for each band at this intensity
*/
while ((redbottom < 256) && (redbottom < redtop))
redvalue[redbottom++]= xcolor.pixel & visual->red_mask;
while ((greenbottom < 256) && (greenbottom < greentop))
greenvalue[greenbottom++]= xcolor.pixel & visual->green_mask;
while ((bluebottom < 256) && (bluebottom < bluetop))
bluevalue[bluebottom++]= xcolor.pixel & visual->blue_mask;
}
}
break;
default:
retry: /* this tag is used when retrying because we couldn't get a fit */
index= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
/* private_cmap flag is invalid if not a dynamic visual
*/
switch (visual->class) {
case StaticColor:
case StaticGray:
private_cmap= 0;
}
/* get the colormap to use.
*/
if (private_cmap) { /* user asked us to use a private cmap */
newmap= 1;
fit= 0;
}
else if ((visual == DefaultVisual(disp, scrn)) ||
(visual->class == StaticGray) ||
(visual->class == StaticColor)) {
/* if we're using the default visual, try to alloc colors shareable.
* otherwise we're using a static visual and should treat it
* accordingly.
*/
if (visual == DefaultVisual(disp, scrn))
ximageinfo->cmap= DefaultColormap(disp, scrn);
else
ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
visual, AllocNone);
newmap= 0;
/* allocate colors shareable (if we can)
*/
for (a= 0; a < image->rgb.used; a++) {
xcolor.red= *(image->rgb.red + a);
xcolor.green= *(image->rgb.green + a);
xcolor.blue= *(image->rgb.blue + a);
if (! XAllocColor(disp, ximageinfo->cmap, &xcolor))
if ((visual->class == StaticColor) ||
(visual->class == StaticGray)) {
printf("imageToXImage: XAllocColor failed on a static visual\n");
return(NULL);
}
else {
/* we can't allocate the colors shareable so free all the colors
* we had allocated and create a private colormap (or fit
* into the default cmap if `fit' is true).
*/
XFreeColors(disp, ximageinfo->cmap, index, a, 0);
newmap= 1;
break;
}
*(index + a)= xcolor.pixel;
}
}
else {
newmap= 1;
fit= 0;
}
if (newmap) {
/* either create a new colormap or fit the image into the one we
* have. to create a new one, we create a private cmap and allocate
* the colors writable. fitting the colors is harder, we have to:
* 1. grab the server so no one can goof with the colormap.
* 2. count the available colors using XAllocColorCells.
* 3. free the colors we just allocated.
* 4. reduce the depth of the image to fit.
* 5. allocate the colors again shareable.
* 6. ungrab the server and continue on our way.
* someone should shoot the people who designed X color allocation.
*/
if (fit) {
if (verbose)
printf(" Fitting image into default colormap\n");
XGrabServer(disp);
}
else {
if (verbose)
printf(" Using private colormap\n");
/* create new colormap
*/
ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
visual, AllocNone);
}
for (a= 0; a < image->rgb.used; a++) /* count entries we got */
if (! XAllocColorCells(disp, ximageinfo->cmap, False, NULL, 0,
index + a, 1))
break;
if (fit) {
if (a > 0)
XFreeColors(disp, ximageinfo->cmap, index, a, 0);
if (a <= 2) {
if (verbose) {
printf(" Cannot fit into default colormap, dithering...");
fflush(stdout);
}
image= dither(image, 0);
if (verbose)
printf("done\n");
fit= 0;
lfree(index);
goto retry;
}
}
if (a == 0) {
fprintf(stderr, "imageToXImage: Color allocation failed!\n");
lfree(index);
return(NULL);
}
if (a < image->rgb.used)
image= reduce(image, a, verbose);
if (fit) {
for (a= 0; a < image->rgb.used; a++) {
xcolor.red= *(image->rgb.red + a);
xcolor.green= *(image->rgb.green + a);
xcolor.blue= *(image->rgb.blue + a);
/* if this fails we're in trouble
*/
if (! XAllocColor(disp, ximageinfo->cmap, &xcolor)) {
printf("XAllocColor failed while fitting colormap!\n");
return(NULL);
}
*(index + a)= xcolor.pixel;
}
XUngrabServer(disp);
}
else {
for (b= 0; b < a; b++) {
xcolor.pixel= *(index + b);
xcolor.red= *(image->rgb.red + b);
xcolor.green= *(image->rgb.green + b);
xcolor.blue= *(image->rgb.blue + b);
XStoreColor(disp, ximageinfo->cmap, &xcolor);
}
}
}
break;
}
/* create an XImage and related colormap based on the image type
* we have.
*/
if (verbose) {
printf(" Building XImage...");
fflush(stdout);
}
switch (image->type) {
case IBITMAP:
{ byte *data;
/* we copy the data to be more consistent
*/
data= lmalloc((image->width + 7) / 8 * image->height);
bcopy(image->data, data, ((image->width + 7) / 8) * image->height);
gcv.function= GXcopy;
ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
0, data, image->width, image->height,
8, 0);
ximageinfo->depth= ddepth;
ximageinfo->foreground= *(index + 1);
ximageinfo->background= *index;
ximageinfo->ximage->bitmap_bit_order= MSBFirst;
ximageinfo->ximage->byte_order= MSBFirst;
break;
}
case IRGB:
case ITRUE:
/* modify image data to match visual and colormap
*/
dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
ximageinfo->depth= ddepth;
dpixlen= (dbits + 7) / 8;
switch (visual->class) {
case DirectColor:
case TrueColor:
{ byte *data, *destptr, *srcptr;
Pixel pixval, newpixval;
ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
NULL, image->width, image->height,
8, 0);
data= lmalloc(image->width * image->height * dpixlen);
ximageinfo->ximage->data= (char *)data;
destptr= data;
srcptr= image->data;
switch (image->type) {
case ITRUE:
for (y= 0; y < image->height; y++)
for (x= 0; x < image->width; x++) {
pixval= memToVal(srcptr, image->pixlen);
newpixval= redvalue[TRUE_RED(pixval)] |
greenvalue[TRUE_GREEN(pixval)] | bluevalue[TRUE_BLUE(pixval)];
valToMem(newpixval, destptr, dpixlen);
srcptr += image->pixlen;
destptr += dpixlen;
}
break;
case IRGB:
for (y= 0; y < image->height; y++)
for (x= 0; x < image->width; x++) {
pixval= memToVal(srcptr, image->pixlen);
pixval= redvalue[image->rgb.red[pixval] >> 8] |
greenvalue[image->rgb.green[pixval] >> 8] |
bluevalue[image->rgb.blue[pixval] >> 8];
valToMem(pixval, destptr, dpixlen);
srcptr += image->pixlen;
destptr += dpixlen;
}
break;
default: /* something's broken */
printf("Unexpected image type for DirectColor/TrueColor visual!\n");
exit(0);
}
ximageinfo->ximage->byte_order= MSBFirst; /* trust me, i know what
* i'm talking about */
break;
}
default:
/* only IRGB images make it this far.
*/
/* if our XImage doesn't have modulus 8 bits per pixel, it's unclear
* how to pack bits so we instead use an XYPixmap image. this is
* slower.
*/
if (dbits % 8) {
byte *data, *destdata, *destptr, *srcptr, mask;
Pixel pixmask, pixval;
ximageinfo->ximage = XCreateImage(disp, visual, ddepth, XYPixmap, 0,
NULL, image->width, image->height,
8, 0);
data= (byte *)lmalloc(image->width * image->height * dpixlen);
ximageinfo->ximage->data= (char *)data;
bzero(data, image->width * image->height * dpixlen);
ximageinfo->ximage->bitmap_bit_order= MSBFirst;
ximageinfo->ximage->byte_order= MSBFirst;
linelen= (image->width + 7) / 8;
for (a= 0; a < dbits; a++) {
pixmask= 1 << a;
destdata= data + ((dbits - a - 1) * image->height * linelen);
srcptr= image->data;
for (y= 0; y < image->height; y++) {
destptr= destdata + (y * linelen);
*destptr= 0;
mask= 0x80;
for (x= 0; x < image->width; x++) {
pixval= memToVal(srcptr, image->pixlen);
srcptr += image->pixlen;
if (index[pixval] & pixmask)
*destptr |= mask;
mask >>= 1;
if (mask == 0) {
mask= 0x80;
destptr++;
}
}
}
}
}
else {
byte *data, *srcptr, *destptr;
ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
NULL, image->width, image->height,
8, 0);
dpixlen= (ximageinfo->ximage->bits_per_pixel + 7) / 8;
data= (byte *)lmalloc(image->width * image->height * dpixlen);
ximageinfo->ximage->data= (char *)data;
ximageinfo->ximage->byte_order= MSBFirst; /* trust me, i know what
* i'm talking about */
srcptr= image->data;
destptr= data;
for (y= 0; y < image->height; y++)
for (x= 0; x < image->width; x++) {
valToMem(index[memToVal(srcptr, image->pixlen)], destptr, dpixlen);
srcptr += image->pixlen;
destptr += dpixlen;
}
}
break;
}
}
if (verbose)
printf("done\n");
if (index)
lfree((byte *)index);
if (redvalue) {
lfree((byte *)redvalue);
lfree((byte *)greenvalue);
lfree((byte *)bluevalue);
}
if (image != orig_image)
freeImage(image);
return(ximageinfo);
}
/* Given an XImage and a drawable, move a rectangle from the Ximage
* to the drawable.
*/
void sendXImage(ximageinfo, src_x, src_y, dst_x, dst_y, w, h)
XImageInfo *ximageinfo;
int src_x, src_y, dst_x, dst_y;
unsigned int w, h;
{
XGCValues gcv;
/* build and cache the GC
*/
if (!ximageinfo->gc) {
gcv.function= GXcopy;
if (ximageinfo->ximage->depth == 1) {
gcv.foreground= ximageinfo->foreground;
gcv.background= ximageinfo->background;
ximageinfo->gc= XCreateGC(ximageinfo->disp, ximageinfo->drawable,
GCFunction | GCForeground | GCBackground,
&gcv);
}
else
ximageinfo->gc= XCreateGC(ximageinfo->disp, ximageinfo->drawable,
GCFunction, &gcv);
}
XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
}
/* free up anything cached in the local Ximage structure.
*/
void freeXImage(image, ximageinfo)
Image *image;
XImageInfo *ximageinfo;
{
if (ximageinfo->gc)
XFreeGC(ximageinfo->disp, ximageinfo->gc);
lfree((byte *)ximageinfo->ximage->data);
ximageinfo->ximage->data= NULL;
XDestroyImage(ximageinfo->ximage);
lfree((byte *)ximageinfo);
}